import xml.etree.ElementTree as ET
import numpy as np 
import os
from .observer import Subject
from .merge_data import merge_data

class DataProcess():

    def __init__(self,taskId,subject,save_dir):
        self.taskId = taskId
        self.subject = subject
        self.save_dir = save_dir

    def data_process(self,pms,slice,sim_nums,sim_dict, sim_dict2):
        results = {}

        nodes_dict={}

        node_lists = []

        state_maping = {'O':1,'F':0,'I':1,'S':1,'M':1}

        for name in sim_dict:
            # 每一个单元的信息
            items_res = {}
            items_res['@name']=name # 加入单元名称
            time_data = sim_dict[name] #某一单元的全部仿真论述的时间数据
            time_data2 = sim_dict2[name]

            dict={}
            mttf_res = 0
            mttr_res = 0
            mttf_len = 0
            mttr_len = 0

            mission_success_nums = 0
            success_last_times = 0 #记录最后时刻的成败状态，用来做似然估计
            for i in range(sim_nums):
                single_time_data = time_data[i]
                single_time_data2 = time_data2[i]
                #print(single_time_data)
                mttf = []
                mttr = []
                state,duration = merge_data(single_time_data)[-1]
                if state_maping[state]:
                    success_last_times += 1
                success_flag=True
                for state,duration in merge_data(single_time_data):
                        if state_maping[state]:
                            mttf.append(duration)
                        else:
                            success_flag = False
                            mttr.append(duration)
                            #if name in pms.models[pms.tasks[index].model_name].all_nodes:
                            #    if pms.models[pms.tasks[index].model_name].all_nodes[name].repair_dist:
                            #m         mttr.append(duration)
                for index,single_phase_time_data in enumerate(single_time_data):  # 单轮带阶段
                    time_points=[]
                    state_points=[]
                    current_time=0
                    cul_time = 0
                    total_time = sum(segment[1] for segment in single_phase_time_data)
                    #print(single_phase_time_data)
                    single_phase_time_data2 = single_time_data[index]
                    

                    for state, duration in single_phase_time_data:
                        #if state_maping[state]:
                        #    mttf.append(duration)
                        #else:
                        #    success_flag = False
                        #    if name in pms.models[pms.tasks[index].model_name].all_nodes:
                        #        if pms.models[pms.tasks[index].model_name].all_nodes[name].repair_dist:
                        #            mttr.append(duration)
                        cul_time = cul_time + duration   
        
                        while current_time<=cul_time:
                            time_points.append(current_time)
                            state_points.append(state_maping[state])
                            current_time = current_time + slice
                    
                    if current_time > total_time and (current_time-total_time)<slice:
                        time_points.append(total_time)
                        state_points.append(state_maping[single_phase_time_data[-1][0]])
                        
                    id = pms.tasks[index].id
                    array = np.array(state_points)
                    #print(single_phase_time_data)
                    if id in dict:
                        dict[id] += array
                    else:
                        dict[id] = array

                if mttf:
                    mttf_res += sum(mttf)
                    mttf_len += len(mttf)
                if mttr:
                    mttr_res += sum(mttr)
                    mttr_len += len(mttr)
                if success_flag:
                        mission_success_nums += 1

            items_res['@mttf'] = mttf_res/mttf_len if mttf_len != 0 else 'inf'
            items_res['@mttr'] = mttr_res/mttr_len if mttr_len != 0 else 'inf'
            items_res['@mttf_MLE'] = mttf_res/(mttf_len-success_last_times) if mttf_len-success_last_times != 0 else 'inf'
            items_res['@mttr_MLE'] = mttr_res/(mttr_len-len(time_data)+success_last_times) if mttr_len-len(time_data)+success_last_times != 0 else 'inf'
            items_res['@msr'] = (mission_success_nums*1.0)/sim_nums
            availability = []
            for p in dict:
                t={}
                t['@id']=p
                t['availability'] = ' '.join([str(i) for i in  dict[p]/sim_nums])
                availability.append(t)
            items_res['@msr'] = (mission_success_nums*1.0)/sim_nums
            availability = []
            for p in dict:
                t={}
                t['@id']=p
                t['availability'] = ' '.join([str(i) for i in  dict[p]/sim_nums])
                availability.append(t)
            items_res['phase'] = availability

            node_lists.append(items_res)

        nodes_dict['ResultNode'] = node_lists
        results['ResultNodes'] = nodes_dict

        return results

    def save2xml(self,pms,slice,sim_nums,sim_dict,sim_dict2):
        results = self.data_process(pms,slice,sim_nums,sim_dict,sim_dict2)
        return self.dict_to_xml_str('ResultNodes',results['ResultNodes'])

    def  str2xml(self,pms,slice,sim_nums,sim_dict,sim_dict2):
        xml_str = self.save2xml(pms,slice,sim_nums,sim_dict,sim_dict2)
        self.save_xml_to_file(xml_str)

    def dict_to_xml(self, tag, d):
        elem = ET.Element(tag)
        for key, val in d.items():
            if isinstance(val, dict):
                child = self.dict_to_xml(key, val)
                elem.append(child)
            elif isinstance(val, list):
                for sub_val in val:
                    child = self.dict_to_xml(key, sub_val)
                    elem.append(child)
            else:
                if key.startswith('@'):
                    elem.set(key[1:], str(val))  # Attribute
                else:
                    child = ET.Element(key)
                    child.text = str(val)
                    elem.append(child)
        return elem

    def dict_to_xml_str(self,tag, d):
        """
        Convert a dictionary to an XML string
        """
        elem = self.dict_to_xml(tag, d)
        return ET.tostring(elem, encoding='unicode')

    def save_xml_to_file(self, xml_str):
        """
        Save XML string to a file
        """
        if not os.path.exists(self.save_dir):
            os.mkdir(self.save_dir)
        file_path = os.path.join(self.save_dir,"result.xml")
        with open(file_path, 'w', encoding='utf-8') as file:
            file.write(xml_str)
        if isinstance(self.subject,Subject):
            self.subject.notify_observers({self.taskId+'calcprog': 100})